home *** CD-ROM | disk | FTP | other *** search
/ Netware Super Library / Netware Super Library.iso / drivers / nics / pktdrv7 / ne1000.asm < prev    next >
Encoding:
Assembly Source File  |  1990-08-29  |  28.8 KB  |  1,142 lines

  1. ; Packet driver for Novell's NE1000 
  2. ; Written by:
  3. ;    Eric Henderson
  4. ;    Brigham Young University
  5. ;    
  6. ; Based on the "generic" packet driver by Russell Nelson with help
  7. ; from the western digital pd by Russell Nelson.
  8. ; 80[123]86 processor support lifted from 3com driver by permission
  9. ;    from Russell Nelson
  10. ; Receive mode support lifted from Western Digital driver
  11. ;
  12. ;   Portions (C) Copyright 1989 BYU
  13.  
  14. version    equ    4
  15.  
  16.     include    defs.asm
  17.  
  18. code    segment    word public
  19.     assume    cs:code, ds:code
  20.  
  21. ;*****************************************************************************
  22. ;
  23. ;    NE1000 controller board offsets
  24. ;    IO port definition (BASE in io_addr)
  25. ;*****************************************************************************
  26. ADDROM  EQU    10h            ; LAN Address ROM
  27. RACK    EQU    10h            ; NE1000 Port Window (?)
  28. NERESET EQU    1fh            ; Issue a read for reset
  29. ; 8390 LAN Controller (page0) register offset for read and write 
  30. CMDR    EQU    00h            ; command register for read & write
  31. CLDA0    EQU    01h            ; current local dma addr 0 for read
  32. PSTART    EQU    01h            ; page start register for write
  33. CLDA1    EQU    02h            ; current local dma addr 1 for read
  34. PSTOP    EQU    02h            ; page stop register for write
  35. BNRY    EQU    03h            ; boundary reg for rd and wr
  36. TSR    EQU    04h            ; tx status reg for rd
  37. TPSR    EQU    04h            ; tx start page start reg for wr    
  38. NCR    EQU    05h            ; number of collision reg for rd
  39. TBCR0    EQU    05h            ; tx byte count 0 reg for wr
  40. FIFO    EQU    06h            ; FIFO for rd
  41. TBCR1    EQU    06h            ; tx byte count 1 reg for wr
  42. ISR    EQU    07h            ; interrupt status reg for rd and wr
  43. CRDA0    EQU    08h            ; current remote dma address 0 for rd
  44. RSAR0    EQU    08h            ; remote start address reg 0  for wr
  45. CRDA1    EQU    09h            ; current remote dma address 1 for rd
  46. RSAR1    EQU    09h            ; remote start address reg 1 for wr
  47. RBCR0    EQU    0Ah            ; remote byte count reg 0 for wr
  48. RBCR1    EQU    0Bh            ; remote byte count reg 1 for wr
  49. RSR    EQU    0Ch            ; rx status reg for rd
  50. RCRWD    EQU    0Ch            ; rx configuration reg for wr
  51. CNTR0    EQU    0Dh            ; tally cnt 0 for frm alg err for rd
  52. TCR    EQU    0Dh            ; tx configuration reg for wr
  53. CNTR1    EQU    0Eh            ; tally cnt 1 for crc err for rd
  54. DCR    EQU    0Eh            ; data configuration reg for wr
  55. CNTR2    EQU    0Fh            ; tally cnt 2 for missed pkt for rd
  56. IMR    EQU    0Fh            ; interrupt mask reg for wr
  57. ; 8390 LAN Controller (page1) register offset for read and write 
  58. PAR0    EQU    01h             ; physical addr reg 0 for rd and wr
  59. PAR1    EQU    02h             ; physical addr reg 1 for rd and wr
  60. PAR2    EQU    03h             ; physical addr reg 2 for rd and wr
  61. PAR3    EQU    04h             ; physical addr reg 3 for rd and wr
  62. PAR4    EQU    05h             ; physical addr reg 4 for rd and wr
  63. PAR5    EQU    06h             ; physical addr reg 5 for rd and wr
  64. CURR    EQU    07h            ; current page reg for rd and wr
  65. MAR0    EQU    08h            ; multicast addr reg 0 fro rd and WR
  66. MAR1    EQU    09h            ; multicast addr reg 1 fro rd and WR
  67. MAR2    EQU    0Ah            ; multicast addr reg 2 fro rd and WR
  68. MAR3    EQU    0Bh            ; multicast addr reg 3 fro rd and WR
  69. MAR4    EQU    0Ch            ; multicast addr reg 4 fro rd and WR
  70. MAR5    EQU    0Dh            ; multicast addr reg 5 fro rd and WR
  71. MAR6    EQU    0Eh            ; multicast addr reg 6 fro rd and WR
  72. MAR7    EQU    0Fh            ; multicast addr reg 7 fro rd and WR
  73.  
  74. ;***********************************************************************
  75. ;
  76. ;    8003 control register operations
  77. ;***********************************************************************
  78.  
  79. MSK_RESET    EQU    80h            ; reset LAN controller
  80. MSK_ENASH    EQU    40h        ; enable PC access to shared mem
  81. MSK_DECOD    EQU    3Fh         ; ???? memory decode bits, corresponding
  82.                     ; to SA 18-13. SA 19 assumed to be 1
  83. ;***********************************************************************
  84. ;
  85. ;    8390 CMDR MASK
  86. ;***********************************************************************
  87.  
  88. MSK_STP        EQU    01h        ; software reset, take 8390 off line
  89. MSK_STA        EQU    02h        ; activate the 8390 NIC
  90. MSK_TXP        EQU    26h        ; initial txing of a frm  (With DMA)
  91. MSK_RD2        EQU    20h        ; abort remote DMA
  92. MSK_PG0        EQU    00h        ; select register page 0
  93. MSK_PG1        EQU    40h        ; select register page 1
  94. MSK_PG2        EQU    80h        ; select register page 2
  95. MSK_DMA_RD    EQU    0ah        ; start DMA read
  96. MSK_DMA_WR    EQU    12h        ; start DMA write
  97.  
  98. ;***********************************************************************
  99. ;
  100. ;    8390 ISR & IMR MASK
  101. ;***********************************************************************
  102.  
  103. MSK_PRX  EQU    01h        ; rx with no error
  104. MSK_PTX  EQU    02h        ; tx with no error
  105. MSK_RXE  EQU    04h        ; rx with error
  106. MSK_TXE  EQU    08h        ; tx with error
  107. MSK_OVW  EQU    10h        ; overwrite warning
  108. MSK_CNT  EQU    20h        ; MSB of one of the tally counters is set
  109. MSK_RDC  EQU    40h        ; remote dma completed
  110. MSK_RST     EQU    80h        ; reset state indicator
  111. UnmaskByte        equ    1fh
  112. InterruptMask        equ    0fh
  113.  
  114. ;***********************************************************************
  115. ;
  116. ;    8390 DCR MASK
  117. ;***********************************************************************
  118.  
  119. MSK_WTS EQU    01h        ; word transfer mode selection
  120. MSK_BOS    EQU    02h        ; byte order selection
  121. MSK_LAS    EQU    04h        ; long addr selection
  122. MSK_BMS    EQU    08h        ; burst mode selection
  123. MSK_ARM    EQU    10h        ; atuoinitialize remote
  124. MSK_FT00 EQU    00h        ; burst lrngth selection
  125. MSK_FT01 EQU    20h        ; burst lrngth selection
  126. MSK_FT10 EQU    40h        ; burst lrngth selection
  127. MSK_FT11 EQU    60h        ; burst lrngth selection
  128.  
  129. ;***********************************************************************
  130. ;
  131. ;    8390 RCR MASK
  132. ;***********************************************************************
  133.  
  134. MSK_SEP EQU    01h        ; save error pkts
  135. MSK_AR     EQU    02h        ; accept runt pkt
  136. MSK_AB     EQU    04h        ; accept broadcast 
  137. MSK_AM     EQU    08h        ; accept multicast 
  138. MSK_PRO    EQU    10h        ; promiscuous physical
  139.                 ; accept all pkt with physical adr
  140. MSK_MON EQU    20h        ; monitor mode
  141.  
  142. ;***********************************************************************
  143. ;
  144. ;    8390 TCR MASK
  145. ;***********************************************************************
  146.  
  147. MSK_CRC EQU    01h        ; inhibit CRC, do not append crc
  148. MSK_LB01 EQU    06h        ; encoded loopback control
  149. MSK_ATD    EQU    08h        ; auto tx disable
  150. MSK_OFST EQU    10h        ; collision offset enable 
  151.  
  152. ;***********************************************************************
  153. ;
  154. ;    8390 RSR MASK
  155. ;***********************************************************************
  156.  
  157. SMK_PRX  EQU    01h        ; rx without error
  158. SMK_CRC  EQU    02h        ; CRC error
  159. SMK_FAE  EQU    04h        ; frame alignment error
  160. SMK_FO   EQU    08h        ; FIFO overrun
  161. SMK_MPA  EQU    10h        ; missed pkt
  162. SMK_PHY  EQU    20h        ; physical/multicase address
  163. SMK_DIS  EQU    40h        ; receiver disable. set in monitor mode
  164. SMK_DEF     EQU    80h        ; deferring
  165.  
  166. ;***********************************************************************
  167. ;
  168. ;    8390 TSR MASK
  169. ;***********************************************************************
  170.  
  171. SMK_PTX  EQU    01h        ; tx without error
  172. SMK_DFR  EQU    02h        ; non deferred tx
  173. SMK_COL  EQU    04h        ; tx collided
  174. SMK_ABT  EQU    08h        ; tx aboort because of excessive collisions
  175. SMK_CRS  EQU    10h        ; carrier sense lost
  176. SMK_FU   EQU    20h        ; FIFO underrun
  177. SMK_CDH  EQU    40h        ; collision detect heartbeat
  178. SMK_OWC     EQU    80h        ; out of window collision
  179.  
  180. ;***********************************************************************
  181. ;
  182. ;    on board memory constant definition
  183. ;***********************************************************************
  184. ; for rcv buff ring of onboard mem
  185. START_PG EQU    26h                  ; start at page 26
  186. STOP_PG  EQU    40h            ; end at page 40 
  187. ; for tx buff of shr mem
  188. TB_SIZE EQU    1            ; number of tb buff in shr mem
  189. TB_PGNO EQU    6            ; number of pages in one tb buff
  190.  
  191.  
  192.     public    int_no, io_addr
  193. int_no        db    3,0,0,0        ;must be four bytes long for get_number.
  194. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  195. my_eaddr      db    EADDR_LEN dup(?) ; 6 byte LAN address
  196. m_channel     dw     0        ; micro channel flag    
  197. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  198.  
  199. rd_NE    MACRO    port
  200.     mov    DX, CS:io_addr
  201.     add    DX, port        ; DX contains address of port
  202.     in    AL, DX            ; AL contains data read from port
  203.     ENDM
  204.  
  205. wr_NE    MACRO    port
  206.     mov    DX, CS:io_addr
  207.     add    DX, port        ; DX contains address of port
  208.     out    DX, AL            ; AL contains data to be written to port
  209.     ENDM
  210.  
  211. ReceiveHeaderStructure    struc
  212.    RReceiveStatus    db    ?
  213.    RNextBuffer        db    ?
  214.    RByteCount        dw    ?
  215.  
  216.    RDestinationAddress    db    EADDR_LEN dup(?)
  217.    RSourceAddress    db    EADDR_LEN dup(?)
  218.    RPacketLength    dw    ?
  219.    RChecksum        dw    ?
  220.    RRPacketLength    dw    ?
  221.    RTranControl        db    ?
  222.    RHPacketType        db    ?
  223.    RDestinationNet    db    4 dup(?)
  224.    RDestinationNode    db    EADDR_LEN dup(?)
  225.    RDestinationSocket    dw    ?
  226. ReceiveHeaderStructure    ends
  227.  
  228. ReceiveHeader    ReceiveHeaderStructure    <>
  229.  
  230. EN_RBUF_NHDR    equ    4    ; Length of controller header bytes
  231.  
  232. BLUEBOOK    equ    1
  233. IEEE8023    equ    11h
  234.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  235. driver_class    db    BLUEBOOK, 0    ;from the packet spec
  236. driver_type    dw    53        ;Wild card matches any type
  237. driver_name    db    'NE1000',0    ;name of the driver.
  238. driver_function    db    2
  239. parameter_list    label    byte
  240.     db    1    ;major rev of packet driver
  241.     db    9    ;minor rev of packet driver
  242.     db    14    ;length of parameter list
  243.     db    EADDR_LEN    ;length of MAC-layer address
  244.     dw    GIANT    ;MTU, including MAC headers
  245.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  246.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  247.     dw    0    ;(# of successive xmits) - 1
  248. int_num    dw    0    ;Interrupt # to hook for post-EOI
  249.             ;processing, 0 == none,
  250.  
  251. mcast_list_bits db      0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
  252. mcast_all_flag  db      0               ;Non-zero if hware should have all
  253.                     ; ones in mask rather than this list.
  254.  
  255.     public    rcv_modes
  256. rcv_modes    dw    7        ;number of receive modes in our table.
  257.         dw    0        ;there is no mode 1.
  258.         dw    rcv_mode_1
  259.         dw    rcv_mode_2
  260.         dw    rcv_mode_3
  261.         dw    rcv_mode_4
  262.         dw    rcv_mode_5
  263.         dw    rcv_mode_6
  264. rxcr_bits       db      MSK_AB        ; Default to ours plus multicast
  265.  
  266.     public    as_send_pkt
  267. ; The Asynchronous Transmit Packet routine.
  268. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  269. ;   interrupts possibly enabled.
  270. ; Exit with nc if ok, or else cy if error, dh set to error number.
  271. ;   es:di and interrupt enable flag preserved on exit.
  272. as_send_pkt:
  273.     ret
  274.  
  275.     public    drop_pkt
  276. ; Drop a packet from the queue.
  277. ; Enter with es:di -> iocb.
  278. drop_pkt:
  279.     assume    ds:nothing
  280.     ret
  281.  
  282.     public    xmit
  283. ; Process a transmit interrupt with the least possible latency to achieve
  284. ;   back-to-back packet transmissions.
  285. ; May only use ax and dx.
  286. xmit:
  287.     assume    ds:nothing
  288.     ret
  289.  
  290.  
  291.     public    send_pkt
  292. send_pkt:
  293. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  294. ;  (only if the high-performance bit is set in driver_function)
  295. ;enter with ds:si -> packet, cx = packet length.
  296. ;exit with nc if ok, or else cy if error, dh set to error number.
  297.     assume    ds:nothing
  298. ; get txblk length                          
  299.     inc    cx
  300.     and    cl, 0feh
  301.     cmp    CX, RUNT
  302.     jnb    length_ok
  303.     mov    cx, RUNT
  304. length_ok:
  305.     cmp    cx, GIANT
  306.     jbe    length1_ok
  307.     mov    dh, NO_SPACE
  308.     stc    
  309.     jmp    count_out_err
  310. length1_ok:
  311. ;new stuff
  312.     mov    AX, CX
  313.     wr_NE    TBCR0            ; Transmit byte count
  314.     mov    al, ah
  315.     wr_NE    TBCR1
  316.     mov    al, 0
  317.     wr_NE    RSAR0
  318.     mov    al, 20h
  319.     wr_NE    RSAR1
  320.     mov    ax, cx
  321.     wr_NE    RBCR0            ; Remote byte count
  322.     mov    al, ah
  323.     wr_NE    RBCR1
  324.  
  325.  
  326. ; Clear out DMA complete interrupt
  327.     mov    al, MSK_PG0        
  328.     wr_NE    CMDR
  329.     mov    al, 40h
  330.     wr_NE    ISR
  331.  
  332.     mov    al, MSK_DMA_WR
  333.     wr_NE    CMDR
  334.  
  335.     mov    DX, CS:io_addr
  336.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  337.  
  338.     cmp    is_186,0    ; Can we use rep outsb?
  339.     je    out86        ; no - have to do it slowly.
  340.     db    0f3h, 06eh    ;masm 4.0 doesn't grok "rep outsb"
  341.     jmp    short ocnteven
  342. out86:
  343.     test    si,1        ; (buf & 1) ?
  344.     jz    obufeven    ; no
  345.     lodsb            ; al = *si++;
  346.     out    dx,al        ; out(dx,al);
  347.     dec    cx        ; cx--;
  348. obufeven:
  349.     mov    di,cx        ; save for later test
  350.     shr    cx,1        ; cx = cnt >> 1; (convert to word count)
  351. ; Do the bulk of the buffer, a word at a time
  352.     jcxz    onobuf        ; if(cx != 0){
  353. xb:    lodsw            ; do { ax = *si++; (si is word pointer)
  354.     out    dx,al        ; out(dx,lowbyte(ax));
  355.     mov    al,ah
  356.     out    dx,al        ; out(dx,hibyte(ax));
  357.     loop    xb        ; } while(--cx != 0); }
  358. ; now check for odd trailing byte
  359. onobuf:    shr    di,1        ; if (di & 1)
  360.     jnc    ocnteven
  361.     lodsb            ;   out(dx,*si++);
  362.     out    dx,al
  363. ocnteven:
  364.     mov    cx, 1000h        ; Prevent infinite loop
  365. WaitForDMAComplete:
  366.     rd_NE    ISR
  367.     test    al, 40h
  368.     jnz    DMAComplete
  369.     loop    WaitForDMAComplete
  370.  
  371. DMAComplete:
  372.     mov    al, MSK_TXP
  373.     wr_NE    CMDR
  374.     clc
  375. exit_now:
  376.     ret
  377.  
  378.  
  379.     public    get_address
  380. get_address:
  381. ;get the address of the interface.
  382. ;enter with es:di -> place to get the address, cx = size of address buffer.
  383. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  384.     assume    ds:code
  385.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  386.     jb    get_addr_x    ; No, fail.
  387.     mov cx,    EADDR_LEN    ; Yes. Set count for loop
  388.     mov    si, offset cs:my_eaddr
  389.     cld            ; Make sure string mode is right
  390.     rep    movsb
  391.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  392.     clc            ; Carry off says success
  393.     ret
  394. get_addr_x:
  395.     stc            ; Tell caller our addr is too big for him
  396.     ret
  397.  
  398.  
  399.     public    set_address
  400. set_address:
  401. ;enter with ds:si -> Ethernet address, CX = length of address.
  402. ;exit with nc if okay, or cy, dh=error if any errors.
  403. ;This proc will set the first CX bytes of the ethernet address, leaving
  404. ; the rest unchanged.
  405.     assume    ds:nothing
  406.  
  407.     cmp    cx, EADDR_LEN
  408.     jbe    set1
  409.     mov    dh, BAD_ADDRESS
  410.     stc
  411.     ret
  412. set1:
  413.     push    es
  414.     push    di
  415.     mov    di, offset my_eaddr
  416.     mov    ax, cs
  417.     mov    es, ax
  418.  
  419.     mov    al, 61h
  420.     wr_NE    CMDR
  421.     mov    DX, CS:io_addr
  422.     add    DX, PAR0        ; DX has address 8390 Phys Address Reg
  423. AddressToChip1:
  424.     lodsb
  425.     out    dx, al
  426.     mov    es:[di], al
  427.     inc    di
  428.     inc    dx
  429.     nop
  430.     nop
  431.     nop    
  432.     nop
  433.     loop    AddressToChip1
  434.     pop    di
  435.     pop    es
  436.  
  437.     mov     al, 21h
  438.     wr_NE     CMDR
  439.     clc
  440.     ret
  441.  
  442.  
  443. ; Routines to set address filtering modes in the DS8390
  444. ;    This was lifted from R. Clements' WD PD
  445. rcv_mode_1:     ; Turn off receiver
  446.     mov al,    MSK_MON      ; Set to monitor for counts but accept none
  447.     jmp short rcv_mode_set
  448. rcv_mode_2:     ; Receive only packets to this interface
  449.     mov al, 0               ; Set for only our packets
  450.     jmp short rcv_mode_set
  451. rcv_mode_3:     ; Mode 2 plus broadcast packets (This is the default)
  452.     mov al,    MSK_AB     ; Set four ours plus broadcasts
  453.     jmp short rcv_mode_set
  454. rcv_mode_4:     ; Mode 3 plus selected multicast packets
  455.     mov al,    MSK_AB+MSK_AM ; Ours, bcst, and filtered multicasts
  456.     mov     mcast_all_flag,0
  457.     jmp short rcv_mode_set
  458. rcv_mode_5:     ; Mode 3 plus ALL multicast packets
  459.     mov al,    MSK_AB+MSK_AM; Ours, bcst, and filtered multicasts
  460.     mov     mcast_all_flag,1
  461.     jmp short rcv_mode_set
  462. rcv_mode_6:     ; Receive all packets (Promiscuous physical plus all multi)
  463.     mov al,    MSK_AB+MSK_AM+MSK_PRO
  464.     mov     mcast_all_flag,1
  465. rcv_mode_set:
  466.     push    ax              ; Hold mode until masks are right
  467.     call    set_8390_multi  ; Set the multicast mask bits in chip
  468.     pop     ax
  469.     WR_NE    RCRWD
  470.     mov     rxcr_bits,al    ; Save a copy of what we set it to
  471.     ret
  472.  
  473.     public    set_multicast_list
  474. set_multicast_list:
  475. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  476. ;return nc if we set all of them, or cy,dh=error if we didn't.
  477.     mov    dh,NO_MULTICAST
  478.     stc
  479.     ret
  480.  
  481. ; Set the multicast filter mask bits in case promiscuous rcv wanted
  482. ;    This was lifted from R. Clements' WD PD
  483. set_8390_multi:
  484.     
  485.     mov    al,MSK_RD2+MSK_PG1
  486.     WR_NE    CMDR 
  487.     mov    cx,8        ; Eight bytes of multicast filter
  488.     mov    si,offset mcast_list_bits  ; Where bits are, if not all ones
  489.     push    cs
  490.     pop     ds
  491.     cli            ; Protect from irq changing page bits
  492.  
  493.     mov    DX, CS:io_addr
  494.     add    DX, MAR0
  495.     mov    al,mcast_all_flag  ; Want all ones or just selected bits?
  496.     or    al,al
  497.     jz    set_mcast_2     ; z = just selected ones
  498.     mov    al,0ffh        ; Ones for filter
  499. set_mcast_all:
  500.     out    dx, al
  501.     inc    dl        ; Step to next one
  502.     jmp    $+2        ; limit chip access rate
  503.     loop    set_mcast_all
  504.     jmp short set_mcast_x
  505.  
  506. set_mcast_2:
  507.     lodsb                   ; Get a byte of mask bits
  508.     out    dx,al        ; Write a mask byte
  509.     inc    dl        ; Step to next I/O register
  510.     jmp    $+2        ; limit chip access rate
  511.     loop    set_mcast_2
  512. set_mcast_x:
  513.     mov    al, MSK_RD2+MSK_PG0
  514.     WR_NE    CMDR
  515.     sti            ; OK for interrupts now
  516.     ret
  517.  
  518.     public    terminate
  519. terminate:
  520.     ret
  521.  
  522.     public    reset_interface
  523. reset_interface:
  524. ;reset the interface.
  525.     assume    ds:code
  526.     mov    al, MSK_STP + MSK_RD2    
  527.     wr_NE    CMDR
  528.     mov al,    0ffh        ; Clear all pending interrupts
  529.     wr_NE    ISR
  530.     xor al,    al        ; Turn off all enables
  531.     wr_NE    IMR
  532.     rd_NE   NERESET        ; Hard reset NE1000
  533.     wr_NE   NERESET
  534.     ret
  535.  
  536.  
  537. ;called when we want to determine what to do with a received packet.
  538. ;enter with cx = packet length, es:di -> packet type.
  539. ;It returns with es:di = 0 if don't want this type or if no buffer available.    
  540.     extrn    recv_find: near
  541.  
  542. ;called after we have copied the packet into the buffer.
  543. ;enter with ds:si ->the packet, cx = length of the packet.
  544.     extrn    recv_copy: near
  545.  
  546.     extrn    count_in_err: near
  547.     extrn    count_out_err: near
  548.  
  549.  
  550.     public    recv
  551. recv:
  552. ;called from the recv isr.  All registers have been saved, and ds=cs.
  553. ;Actually, not just receive, but all interrupts come here.
  554. ;Upon exit, the interrupt will be acknowledged.
  555.     assume    ds:code
  556.  
  557. ; read irq status register
  558.  
  559. rd_isr:
  560.     rd_NE    ISR            ; read isr into AL
  561.     and    AL, 3Fh            ; check bit0-bit5, if all 1's no irq
  562.     cmp    AL, 0            ; if any irq
  563.     jne    tst_ovw            ; some irq
  564.     ret                ; no more irq, exit
  565.  
  566. ; process OVW    (OVW = 1)       
  567. ;    may report error here
  568. tst_ovw:
  569.     test    AL, MSK_OVW        ; if OVW irq
  570.     jnz    prcs_ov            ; OVW (OVW = 1) 
  571.     jmp    test_rx            ; no OVW (OVW = 0) 
  572.  
  573. ; **************************************************************
  574. ; follow the DP8390 datasheet addendum to handle the buff ring overflow
  575. ; 5/1/90 Use Carl Beame's fix
  576. prcs_ov:
  577. ; 1. issue a STOP mode command
  578.     mov    AL, MSK_STP + MSK_RD2
  579.     wr_NE    CMDR
  580.  
  581.     mov    al, MSK_RD2 + MSK_PG1    ;Carl Beame's fix
  582.     wr_NE    CMDR
  583.     rd_NE    CURR
  584.     mov    bl, al
  585.     mov    al, MSK_RD2 + MSK_PG0
  586.  
  587. ; 6. remove one packet from the ring
  588.     rd_NE    BNRY            ; BNRY in AL
  589.     add    AL, 1            ; start page of frm in AL
  590.     cmp    AL, STOP_PG        ; check boundary
  591.         jne    get1
  592.     mov    AL, START_PG        
  593. ; ring not empty
  594. get1:
  595.     cmp    al, bl            ;Check if buffer empty (Beame's fix)
  596.     je    recv_ovr_empty        ;Yes? Don't receive anything
  597.  
  598.     mov    BH, AL            ; BX has the rx_frm pointer
  599.  
  600.     mov    al, SIZE ReceiveHeader
  601.     wr_NE    RBCR0
  602.     xor    al, al
  603.     jmp    $+2
  604.     wr_NE    RBCR1
  605.     jmp    $+2
  606.     wr_NE    RSAR0
  607.     mov    al, bh
  608.     wr_NE    RSAR1
  609.     mov    al, MSK_DMA_RD
  610.     wr_NE    CMDR
  611.  
  612.     mov    DX, CS:io_addr
  613.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  614.     mov    di, OFFSET ReceiveHeader
  615.     mov    ax, cs
  616.     mov    es, ax
  617.     mov    cx, SIZE ReceiveHeader
  618.     
  619. Receive1:
  620.     in    al, dx
  621.     stosb
  622.     loop    Receive1
  623.  
  624. SkipReceive1:
  625.     mov    bx, offset ReceiveHeader
  626.     mov    AL, CS:[BX]        ; AL has the status byte
  627.     test    AL, SMK_PRX        ; if rx good
  628.     jz    fd_bnr            ; rx error, drop frm by forward bnry
  629.  
  630. ; good frm, call _rcv_frm
  631.     call     _rcv_frm           
  632.  
  633. fd_bnr:                    ;drop frm by forward BNRY
  634.     mov    al, cs:ReceiveHeader.RNextBuffer    ; al = next pointer 
  635.     sub    AL, 1            ; new BNRY in AL
  636.     cmp    AL, START_PG        ; check boundary
  637.     jae    wrbnr            ; unsigned arithmetic
  638.     mov    AL, STOP_PG        ;
  639.     dec    AL            ;
  640. wrbnr:
  641.     wr_NE    BNRY
  642.     jmp    $+2            ;
  643. ; 2. clear the remote byte count registers (RBCR0,RBCR1)
  644. recv_ovr_empty:
  645.     xor    AL, AL
  646.     wr_NE    RBCR0
  647.     jmp    $+2            ;
  648.     wr_NE    RBCR1
  649.     jmp    $+2            ;
  650. ; 3. poll the ISR for the RST bit
  651. plisr:
  652.     rd_NE    ISR
  653.     jmp    $+2            ;
  654.     test    AL, MSK_RST
  655.     jz    plisr        ; keep polling until the RST bit set
  656. ; 4. place the NIC in loopback mode (mode 1 or 2) by writing 02 or 04 to TCR
  657.     mov    AL, 02h        ; put it in mode 2 (internal loopback)
  658.     wr_NE    TCR
  659.     jmp    $+2            ;
  660. ; 5. issue start mode command
  661.     mov    AL, MSK_STA + MSK_RD2
  662.     wr_NE    CMDR
  663.     jmp    $+2            ;
  664. ; 7. out from loopback mode by writing 00 to TCR
  665.     xor    AL, AL
  666.     wr_NE    TCR        ; normal operation configuration
  667.     jmp    $+2            ;
  668. ; clear OVW in ISR              
  669.     mov    AL, MSK_OVW 
  670.     wr_NE    ISR            ; clear OVW
  671.     call    count_in_err        ; increment overflow counter
  672.     jmp    rd_isr            ; back to the top
  673.  
  674.  
  675. ; end of the modification 
  676. ; *****************************************************
  677. ;    
  678. ;process PRX and RXE
  679. ;
  680. test_rx:        
  681.     test      AL, MSK_PRX    
  682.     jnz    prcs_rx                 ; PRX = 1
  683.     test     AL, MSK_RXE        
  684.     jnz    prcs_rxe        ; RXE = 1
  685.     jmp    test_tx
  686.  
  687. prcs_rxe:
  688.     call    count_in_err
  689. prcs_rx:
  690.     mov    AL, MSK_PG1 + MSK_RD2    ; read CURR reg
  691.     wr_NE    CMDR
  692.     jmp    $+2
  693.     rd_NE    CURR
  694.     jmp    $+2
  695.     mov    BL, AL            ; CURR in BL 
  696.     mov    AL, MSK_PG0 + MSK_RD2    ; read BNRY reg
  697.     wr_NE  CMDR
  698.     jmp    $+2
  699.     rd_NE    BNRY            ; BNRY in AL
  700.     add    AL, 1            ; start page of frm in AL
  701.     cmp    AL, STOP_PG         ; check boundary
  702.     jne    go_cmp
  703.     mov    AL, START_PG         ;         
  704. go_cmp:
  705.     cmp    AL, BL            
  706.     je    end_rx            ; buff ring empty
  707.  
  708. ; Ring Not Empty
  709.     wr_NE    RSAR1
  710.     jmp    $+2
  711.     xor    al, al
  712.     jmp    $+2
  713.     wr_NE    RBCR1
  714.     jmp    $+2
  715.     wr_NE    RSAR0
  716.     mov    al, SIZE ReceiveHeader
  717.     wr_NE    RBCR0
  718.     mov    al, MSK_DMA_RD
  719.     wr_NE    CMDR
  720.  
  721.     mov    DX, CS:io_addr
  722.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  723.     mov    di, OFFSET ReceiveHeader
  724.     mov    ax, cs
  725.     mov    es, ax
  726.     mov    cx, SIZE ReceiveHeader
  727.  
  728. Receive2:
  729.     in    al, dx
  730.     stosb
  731.     loop    Receive2
  732.  
  733. SkipReceive2:
  734.     mov    bx, offset ReceiveHeader
  735.     mov    AL, CS:[BX]        ; AL has the status byte
  736.     test    AL, SMK_PRX        ; if rx good
  737.     jz    fd_bnry            ; rx error, drop frm by forward bnry
  738.  
  739. ; good frm, call _rcv_frm
  740.        call     _rcv_frm           
  741.  
  742. fd_bnry:                ; drop frm by forward BNRY
  743.     mov    al, CS:ReceiveHeader.RNextBuffer    ; al = next pointer 
  744.     sub    AL, 1            ; new BNRY in AL
  745.     cmp    AL, START_PG        ; check boundary
  746.     jae    wrbnry            ; unsigned arithmetic
  747.     mov    AL, STOP_PG        ;
  748.     dec    AL            ;
  749. wrbnry:
  750.     wr_NE    BNRY
  751.     jmp    prcs_rx     
  752.        
  753. ; clear PRX, RXE, OVW in ISR              
  754. end_rx:
  755.     mov    AL, MSK_OVW + MSK_RXE + MSK_PRX
  756.     wr_NE    ISR            ; clear OVW, RXE, PRX
  757.     jmp    rd_isr            ; back to the top
  758.  
  759. ;process PTX and TXE
  760. test_tx:
  761.     test      AL, MSK_PTX    
  762.     jnz    prc_ptx                 ; PTX = 1
  763.     test     AL, MSK_TXE        
  764.     jnz    prc_txe            ; TXE = 1
  765.     jmp    test_cnt
  766.       
  767.  
  768. ; process tx good, update txok, lostcrs, collsn
  769. prc_ptx:                ; tx good 
  770.     rd_NE    TSR
  771.     test    AL, SMK_CRS        ; is crs set in TSR
  772.     jz    nocrs            ; no               
  773. nocrs:    
  774.     rd_NE    NCR            ; read number of collision in AL
  775.     mov    AL, MSK_PTX
  776.     wr_NE    ISR            ; clear PTX
  777.     jmp    rd_isr
  778.  
  779. ; process tx error, update .txbad .underrun
  780. prc_txe:                ; tx bad
  781.     call    count_out_err    
  782.     rd_NE    TSR
  783.     test    AL, SMK_FU        ; it fu set in TSR
  784.     jz    nofu            ; no               
  785. nofu:                                  
  786.         mov    AL, MSK_TXE
  787.     wr_NE    ISR            ; clear PTX
  788.     jmp    rd_isr
  789.  
  790. ; process counter overflow, update .algerr .crcerr .???(missed pkt)
  791. test_cnt:
  792.     test      AL, MSK_CNT    
  793.     jnz    prc_cnt            ; yes, process cnt
  794.     jmp    rd_isr                 ; no CNT irq, back to the top
  795. ; process CNT            
  796. prc_cnt:
  797.     mov    AL, MSK_CNT
  798.     wr_NE    ISR            ; clear CNT
  799.     jmp    rd_isr            ; back to the top
  800.  
  801. ; End of RECV
  802.  
  803. _rcv_frm:
  804.     
  805. ; read byte count 
  806.     mov     cx, cs:ReceiveHeader.RByteCount    ; Extract size of frame
  807.     sub    CX, EN_RBUF_NHDR            ; 4 control bytes
  808.     cmp    CX, GIANT
  809.     jbe    rxlen_ok
  810.     mov    CX, GIANT
  811. rxlen_ok:
  812.     mov    AX, cs
  813.     mov    ES, AX
  814.     mov     di, offset cs:ReceiveHeader.RPacketLength
  815.  
  816.     push    cx            ; Save frame size
  817.     push    es
  818.  
  819.     mov ax,    cs            ; Set ds = code
  820.     mov ds,    ax
  821.     assume    ds:code
  822.     call    recv_find        ; See if type and size are wanted
  823.                     ;     CX = packet length
  824.                     ;    ES:DI = packet type
  825.  
  826.     pop    ds            ; RX page pointer in ds now
  827.     assume    ds:nothing
  828.     pop    cx
  829.  
  830.     cld                ; Copies below are forward
  831.     mov ax,    es            ; Did recv_find give us a null pointer?
  832.     or  ax,    di            ; ..
  833.     je    no_buff            ; If null, don't copy the data    
  834. has_buf:  
  835.  
  836. ;Tell DMA to copy the whole packet for us
  837.     mov    ax, EN_RBUF_NHDR    
  838.     wr_NE    RSAR0        ; Don't copy  4 8390 control bytes
  839.     mov    ax, cx        ; CX has byte count
  840.     wr_NE    RBCR0        ; LSB first
  841.     mov    al, ah
  842.     wr_NE    RBCR1        ; Now MSB
  843.  
  844.     mov    al, MSK_DMA_RD  ; Issue DMA read command
  845.     wr_NE    CMDR
  846.  
  847. ; copy from NE1000 on board memory using the window RACK
  848. ; use IN and stosb to do the copy, IN -> AX -> ES:DI (CX has byte count)                        
  849.  
  850. copynow:
  851.     push    cx        ; We will want the count and pointer
  852.     push    es        ;  to hand to client after copying,
  853.     push    di        ;  so save them at this point
  854.  
  855.     mov    DX, CS:io_addr
  856.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  857.  
  858.     cmp    is_186,0    ; Can we use rep insb?
  859.     je    in86        ; no - have to do it slowly.
  860.     db    0f3h, 06ch    ;masm 4.0 doesn't grok "rep insb"
  861.     jmp    short icnteven
  862. in86:
  863. ; If buffer doesn't begin on a word boundary, get the first byte
  864.     test    di,1    ; if(buf & 1){
  865.     jz    ibufeven ;
  866.     in    al,dx    ; al = in(dx);
  867.     stosb        ; *di++ = al
  868.     dec    cx    ; cx--;
  869. ibufeven:
  870.     mov    si,cx    ; size = cx;
  871.     shr    cx,1    ; cx = cnt >> 1; (convert to word count)
  872. ; Do the bulk of the buffer, a word at a time
  873.     jcxz    inobuf    ; if(cx != 0){
  874. rb:    in    al,dx    ; do { al = in(dx);
  875.     mov    ah,al
  876.     in    al,dx    ; ah = in(dx);
  877.     xchg    al,ah
  878.     stosw        ; *si++ = ax; (di is word pointer)
  879.     loop    rb    ; } while(--cx != 0);
  880. ; now check for odd trailing byte
  881. inobuf:    shr    si,1
  882.     jnc    icnteven
  883.     in    al,dx
  884.     stosb        ; *di++ = al
  885. icnteven:
  886.  
  887. call_rc:
  888.     pop    si            ; Recover pointer to destination
  889.     pop    ds            ; Tell client it's his source
  890.     pop    cx            ; And it's this long
  891.     assume    ds:nothing
  892.     call    recv_copy        ; Give it to him
  893.     jmp    short rcv_ret
  894.  
  895. ; no system buff availble to hold rx frm
  896. no_buff:
  897. rcv_ret:
  898.     push    cs        ; Put ds back in code space
  899.     pop    ds        ; ..
  900.     assume    ds:code
  901.     ret
  902.  
  903.  
  904.  
  905.     public    recv_exiting
  906. recv_exiting:
  907. ;called from the recv isr after interrupts have been acknowledged.
  908. ;Only ds and ax have been saved.
  909.     assume    ds:nothing
  910.     ret
  911.  
  912.  
  913. ;any code after this will not be kept after initialization.
  914. end_resident    label    byte
  915.  
  916.  
  917.     public    usage_msg
  918. usage_msg    db    "usage: NE1000 [-n] [-d] [-w] <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  919.  
  920.     public    copyright_msg
  921. copyright_msg    db    "Packet driver for NE1000, version "
  922.         db    '0'+majver,".",'0'+version,CR,LF
  923.         db    "Portions Copyright 1989, Eric Henderson, BYU",CR,LF,'$'
  924. int_no_name    db    "Interrupt number ",'$'
  925. io_addr_name    db    "I/O port ",'$'
  926. no_board_msg:
  927.     db    "NE1000 apparently not present at this IO address.",CR,LF,'$'
  928. HardwareFailure:
  929.     db    "The NE1000 is not responding.",CR,LF,'$'
  930. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  931.  
  932.     extrn    set_recv_isr: near
  933.  
  934. ;enter with si -> argument string, di -> word to store.
  935. ;if there is no number, don't change the number.
  936.     extrn    get_number: near
  937.  
  938. ;enter with dx -> name of word, di -> dword to print.
  939.     extrn    print_number: near
  940.  
  941.     public    parse_args
  942. parse_args:
  943. ;exit with nc if all went well, cy otherwise.
  944.     mov    di,offset int_no
  945.     call    get_number
  946.     mov    di,offset io_addr
  947.     call    get_number
  948.     clc
  949.     ret
  950.  
  951.     extrn    etopen_diagn: byte
  952.  
  953. BoardNotResponding:
  954.     mov    dx, offset HardwareFailure
  955.     mov    etopen_diagn, 35
  956.     jmp    short error_wrt
  957. bad_cksum:
  958. no_memory:
  959.     mov    dx,offset no_board_msg
  960.     mov    etopen_diagn,37
  961. error_wrt:
  962.     mov    ah,9
  963.     int    21h
  964.     stc
  965.     ret
  966.  
  967.     public    etopen
  968. etopen:
  969. ;if all is okay,
  970.  
  971.     ; reset NE1000 board 
  972.     rd_NE    NERESET
  973.     wr_NE    NERESET
  974.     mov    al, 21h
  975.     wr_NE    CMDR
  976.  
  977.     ; Test to see if we're OK
  978.     rd_NE    CMDR
  979.     cmp    al, 21h
  980.     je    WeBeOK
  981.     jmp    BoardNotResponding
  982.  
  983. WeBeOK:
  984.     mov    al, 0
  985.     wr_NE    DCR        
  986.     mov    al, 60h
  987.     wr_NE    TPSR        
  988.     mov    al, 0
  989.     wr_NE    TCR        
  990.     mov    al, 20h
  991.     wr_NE    RCRWD        
  992.     mov    al, 4
  993.     wr_NE    PSTART        
  994.     mov    al, 4
  995.     wr_NE    BNRY        
  996.     mov    al, 0ffh
  997.     wr_NE    PSTOP        
  998.     mov    al, 3ch
  999.     wr_NE    TBCR0        
  1000.     mov    al, 0
  1001.     wr_NE    TBCR1        
  1002.     mov    al, 0ffh
  1003.     wr_NE    ISR        
  1004.     mov    al, 61h
  1005.     wr_NE    CMDR        
  1006.     mov    al, 4
  1007.     wr_NE    CURR        
  1008.     mov    al, 22h
  1009.     wr_NE    CMDR        
  1010.  
  1011.     ; Test to see if we're still OK
  1012.     rd_NE    CMDR
  1013.     cmp    al, 22h
  1014.     je    WeBeStillOK
  1015.     jmp    BoardNotResponding
  1016.  
  1017. WeBeStillOK:
  1018.  
  1019.     ; set up my_eaddr from addr ROM 
  1020.     mov    al, 21h
  1021.     wr_NE    CMDR
  1022.     mov    al, EADDR_LEN
  1023.     wr_NE    RBCR0
  1024.     mov    al, 0
  1025.     wr_NE    RBCR1
  1026.     wr_NE    RSAR0
  1027.     wr_NE    RSAR1
  1028.     mov    al, MSK_DMA_RD
  1029.     wr_NE    CMDR
  1030.  
  1031.     mov    DX, CS:io_addr
  1032.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  1033.     mov    di, OFFSET my_eaddr
  1034.     mov    ax, cs
  1035.     mov    es, ax
  1036.     mov    cx, EADDR_LEN
  1037. GetEnetAddress:
  1038.     in    al, dx
  1039.     stosb
  1040.     loop    GetEnetAddress
  1041.  
  1042.     mov    ax, cs
  1043.     mov    ds, ax
  1044.     mov    si, OFFSET my_eaddr
  1045.     mov    cx, EADDR_LEN
  1046.     call    set_address
  1047.  
  1048.     mov     al, 21h
  1049.     wr_NE     CMDR
  1050.  
  1051.     mov    al, START_PG
  1052.     jmp    $+2
  1053.     wr_NE    PSTART
  1054.     jmp    $+2
  1055.     wr_NE    BNRY
  1056.     mov    al, STOP_PG
  1057.     jmp    $+2
  1058.     wr_NE    PSTOP
  1059.  
  1060.     mov    al, MSK_PG1+MSK_RD2+MSK_STP
  1061.     jmp    $+2
  1062.     wr_NE    CMDR
  1063.     mov    al, START_PG + 1
  1064.     jmp    $+2
  1065.     wr_NE    CURR
  1066.  
  1067. ; Clear the multicast filter enables, we don't want any of them.
  1068.     mov cl,    8        ; Eight bytes of multicast filter
  1069.     xor al,    al        ; Zeros for filter
  1070.     mov dx, cs:io_addr    ; Base of multicast filter locations
  1071.     add dx, MAR0        ; ..
  1072. clr_mcast_l:
  1073.     out dx,    al        ; Clear a byte
  1074.     inc    dl        ; Step to next one
  1075.     dec    cl        ; Count 8 filter locs
  1076.     jnz    clr_mcast_l    ; ..    
  1077.  
  1078.     mov    al, 21h
  1079.     jmp    $+2
  1080.     wr_NE    CMDR
  1081.     mov     al, 48h
  1082.     jmp    $+2
  1083.     wr_NE    DCR
  1084.     mov    al, 0
  1085.     jmp    $+2
  1086.     wr_NE    TCR
  1087.     mov    al, MSK_RXE
  1088.     jmp    $+2
  1089.     wr_NE    RCRWD
  1090.     mov    al, 0ffh
  1091.     jmp    $+2
  1092.     wr_NE    ISR
  1093.     mov    al, UnmaskByte
  1094.     jmp    $+2
  1095.     wr_NE    InterruptMask
  1096.  
  1097. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  1098. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  1099.     mov    cl,33
  1100.     mov    ax,0ffffh
  1101.     shl    ax,cl
  1102.     jz    not_186
  1103.     mov    is_186,1
  1104.     mov    dx,offset using_186_msg
  1105.     mov    ah,9
  1106.     int    21h
  1107. not_186:
  1108.  
  1109.     call    set_recv_isr    ; Put ourselves in interrupt chain
  1110.     
  1111.     mov    al, 22h
  1112.     jmp    $+2
  1113.     wr_NE    CMDR    
  1114.  
  1115.     mov    al, int_no        ; Get board's interrupt vector
  1116.     add    al, 8
  1117.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1118.     jb    set_int_num        ; No.
  1119.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1120. set_int_num:
  1121.     xor    ah, ah            ; Clear high byte
  1122.     mov    int_num, ax        ; Set parameter_list int num.
  1123.  
  1124.     mov    dx,offset end_resident
  1125.     clc
  1126.     ret
  1127.  
  1128.     public    print_parameters
  1129. print_parameters:
  1130. ;echo our command-line parameters
  1131.     mov    di,offset int_no
  1132.     mov    dx,offset int_no_name
  1133.     call    print_number
  1134.     mov    di,offset io_addr
  1135.     mov    dx,offset io_addr_name
  1136.     call    print_number
  1137.     ret
  1138.  
  1139. code    ends
  1140.  
  1141.     end
  1142.